"""
Fingerprint data model for content originality detection.
"""
from datetime import datetime, timezone
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field, ConfigDict, field_validator
from bson import ObjectId


class ContentFingerprint(BaseModel):
    """Content fingerprint data model for MongoDB storage."""
    
    model_config = ConfigDict(
        arbitrary_types_allowed=True,
        json_encoders={ObjectId: str}
    )
    
    id: Optional[str] = Field(None, alias="_id")
    content_id: str = Field(..., description="Associated content/article ID")
    content_type: str = Field(..., description="Type: article/paragraph/sentence")
    fingerprint: str = Field(..., description="64-bit SimHash value")
    text_preview: str = Field(..., max_length=200, description="Text preview (first 200 chars)")
    word_count: int = Field(..., gt=0, description="Word count")
    created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
    source: Optional[str] = Field(None, description="Source identifier")
    metadata: Dict[str, Any] = Field(default_factory=dict, description="Additional metadata")
    
    @field_validator('content_type')
    @classmethod
    def validate_content_type(cls, v: str) -> str:
        """Validate content type."""
        valid_types = ['article', 'paragraph', 'sentence']
        if v not in valid_types:
            raise ValueError(f"content_type must be one of {valid_types}")
        return v
    
    @field_validator('fingerprint')
    @classmethod
    def validate_fingerprint(cls, v: str) -> str:
        """Validate fingerprint format (64-bit hex string)."""
        if not v:
            raise ValueError("Fingerprint cannot be empty")
        if len(v) != 16:  # 64 bits = 16 hex chars
            raise ValueError("Fingerprint must be 16 hex characters (64 bits)")
        if not all(c in '0123456789abcdef' for c in v.lower()):
            raise ValueError("Fingerprint must be a valid hex string")
        return v.lower()
    
    def to_mongo(self) -> dict:
        """Convert to MongoDB document format."""
        data = self.model_dump(exclude={'id'})
        if self.id:
            data['_id'] = ObjectId(self.id) if isinstance(self.id, str) else self.id
        return data
    
    @classmethod
    def from_mongo(cls, data: dict) -> 'ContentFingerprint':
        """Create from MongoDB document."""
        if data.get('_id'):
            data['_id'] = str(data['_id'])
        return cls(**data)


class OriginalityReport(BaseModel):
    """Originality check report data model."""
    
    model_config = ConfigDict(
        arbitrary_types_allowed=True,
        json_encoders={ObjectId: str}
    )
    
    id: Optional[str] = Field(None, alias="_id")
    content_id: str = Field(..., description="Checked content ID")
    originality_score: float = Field(..., ge=0, le=100, description="Originality score 0-100")
    similar_contents: List[Dict[str, Any]] = Field(
        default_factory=list,
        description="List of similar content with similarity scores"
    )
    citations_needed: List[Dict[str, Any]] = Field(
        default_factory=list,
        description="Parts that need citations"
    )
    checked_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
    report_url: Optional[str] = Field(None, description="Report file path/URL")
    
    @field_validator('originality_score')
    @classmethod
    def validate_score(cls, v: float) -> float:
        """Validate originality score."""
        return round(v, 2)
    
    def to_mongo(self) -> dict:
        """Convert to MongoDB document format."""
        data = self.model_dump(exclude={'id'})
        if self.id:
            data['_id'] = ObjectId(self.id) if isinstance(self.id, str) else self.id
        return data
    
    @classmethod
    def from_mongo(cls, data: dict) -> 'OriginalityReport':
        """Create from MongoDB document."""
        if data.get('_id'):
            data['_id'] = str(data['_id'])
        return cls(**data)


class SimilarContent(BaseModel):
    """Similar content information."""
    
    content_id: str = Field(..., description="Similar content ID")
    similarity: float = Field(..., ge=0, le=100, description="Similarity percentage")
    fingerprint: str = Field(..., description="Content fingerprint")
    segments: List[Dict[str, Any]] = Field(
        default_factory=list,
        description="Similar segments with positions"
    )
    source: Optional[str] = Field(None, description="Content source")
    
    @field_validator('similarity')
    @classmethod
    def validate_similarity(cls, v: float) -> float:
        """Validate similarity percentage."""
        return round(v, 2)


class CitationSuggestion(BaseModel):
    """Citation suggestion for content that needs attribution."""
    
    text: str = Field(..., description="Text that needs citation")
    position: Dict[str, int] = Field(..., description="Text position (start, end)")
    suggested_source: Optional[str] = Field(None, description="Suggested source")
    citation_format: str = Field(default="APA", description="Citation format")
    confidence: float = Field(..., ge=0, le=1, description="Confidence score")
    
    @field_validator('citation_format')
    @classmethod
    def validate_format(cls, v: str) -> str:
        """Validate citation format."""
        valid_formats = ['APA', 'MLA', 'Chicago', 'Harvard']
        if v not in valid_formats:
            raise ValueError(f"citation_format must be one of {valid_formats}")
        return v